package com.dingreading.cloud.soms.util;

import com.dingreading.cloud.common.util.AccountUtil;
import com.dingreading.cloud.common.util.DoubleUtil;
import com.dingreading.cloud.common.util.NepUtil;
import com.dingreading.cloud.soms.dto.StoreProjectCycleDtoV2;
import com.dingreading.cloud.soms.entity.Cmorders;
import com.dingreading.cloud.soms.entity.Cmservices;
import com.dingreading.cloud.soms.mapper.StoreProjectCycleMapper;
import com.dingreading.cloud.soms.service.CaCallNamesService;
import com.dingreading.cloud.soms.service.CmservicesService;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单金额拆分
 */
@Component
public class OrderAmountSplitUtil {

    @Resource
    private CmservicesService cmservicesService;
    @Resource
    private CaCallNamesService callNamesService;
    @Resource
    private StoreProjectCycleMapper cycleMapper;

    /*创建、更新、变更、退费使用*/
    public String splitServiceAmount(Cmorders cmorders, Double carriedForwardAmount, Double totalRefundAmount) throws Exception {
        // 防止服务数据更新延迟
        TimeUnit.SECONDS.sleep(1);

        String msg = splitAmount(true, cmorders, carriedForwardAmount, totalRefundAmount);
        if (StringUtils.isNotBlank(msg))
            System.out.println(msg);

        return msg;
    }

    /*补充数据使用*/
    @Async
    public void splitServiceAmount(Cmorders cmorders) throws Exception {
        String msg = splitAmount(true, cmorders, cmorders.getCarriedForwardAmount(), null);
        if (StringUtils.isNotBlank(msg))
            System.out.println(msg + cmorders.getOrderCode());
    }

    /*补充数据使用*/
    @Async
    public void splitServiceAmountList(List<Cmorders> list) throws Exception {
        for (Cmorders cmorders : list) {
            String msg = splitAmount(true, cmorders, cmorders.getCarriedForwardAmount(), null);
            if (StringUtils.isNotBlank(msg))
                System.out.println(msg + cmorders.getOrderCode());
        }
        System.out.println("处理完成");
    }

    /**
     * 计算订单的服务课次单价v2
     *
     * @param editOrder            1:创建、更新、变更、退费使用，0:补充数据使用
     * @param carriedForwardAmount 结转金额
     * @param totalRefundAmount    总退款金额
     */
    public String splitAmount(boolean editOrder, Cmorders cmorders, Double carriedForwardAmount, Double totalRefundAmount) throws Exception {
        String orderType = cmorders.getOrderType();
        if (StringUtils.isBlank(orderType))
            return "没有收入类型，订单金额拆分失败";
        Integer orderState = cmorders.getOrderState();
        if (orderState == null)
            return "订单状态未知，订单金额拆分失败";
        if (orderState.equals(3))
            return "订单状态是退费，订单金额拆分失败";

        double orderAmount = 0;
        if (carriedForwardAmount != null)
            orderAmount = DoubleUtil.sum(NepUtil.nullToZero(cmorders.getOrderAmount()), carriedForwardAmount);
        else if (totalRefundAmount != null)
            orderAmount = DoubleUtil.sub(NepUtil.nullToZero(cmorders.getOrderAmount()), totalRefundAmount);
        else
            orderAmount = NepUtil.nullToZero(cmorders.getOrderAmount());

        List<Cmservices> serviceList = cmservicesService.listByOrderCodeAndType(cmorders.getOrderCode(), editOrder);
        if (CollectionUtils.isEmpty(serviceList))
            return "未查询到订单的服务，订单金额拆分失败";

        if (orderAmount <= 0) {
            System.out.println("订单金额为0");
            // 更新服务的单价和课耗的单价为0
            setServiceZero(editOrder, serviceList);
            return "";
        }

        Map<String, List<Cmservices>> serviceMap = serviceList.stream()
                .collect(Collectors.groupingBy(Cmservices::getProjectUid));
        Set<String> projectUidList = new HashSet<>();
        Table<String, Integer, Integer> cntTable = HashBasedTable.create();
        for (Map.Entry<String, List<Cmservices>> entry : serviceMap.entrySet()) {
            String projectUid = entry.getKey();
            List<Cmservices> list = entry.getValue();

            int dayNum = 0;
            int lessonNum = 0;
            for (Cmservices service : list) {
                if (CmorderUtil.isConsumeLesson(service.getLessonStatus(), service.getFreeStatus())) {
                    // 按课次
                    int totalLesson = NepUtil.nullToZero(service.getTotalLessons());
                    if (totalLesson <= 0)
                        return "服务总次数不正确，订单金额拆分失败";
                    lessonNum += totalLesson;
                } else {
                    // 按天数
                    int days = NepUtil.nullToZero(service.getServiceDays());
                    if (days <= 0)
                        return "服务总天数不正确，订单金额拆分失败";
                    dayNum += days;
                }
            }

            if (lessonNum > 0) {
                // 按次数
                cntTable.put(projectUid, 1, lessonNum);
            } else {
                // 按天数
                cntTable.put(projectUid, 0, dayNum);
            }
            projectUidList.add(projectUid);
        }

        if (CollectionUtils.isEmpty(projectUidList))
            return "未发现可拆分的服务，订单金额拆分失败";

        // 按门店uid、服务uid、次数或天数，查询最接近的单价
        Map<String, Double> projectUnitAmountMap = getProjectUnitAmountMap(cmorders.getCorpUid(), cmorders.getStoreUid(), cntTable);
        if (projectUnitAmountMap == null)
            return "请前往 门店服务管理 维护相关数据";

        double projectTotalAmountCnt = 0;
        Map<String, Double> projectTotalAmountMap = new HashMap<>();
        for (Table.Cell<String, Integer, Integer> cell : cntTable.cellSet()) {
            String projectUid = cell.getRowKey();
            Integer consumeType = cell.getColumnKey();
            Integer cnt = cell.getValue();

            double projectTotalAmount = 0;
            double projectUnitAmount = projectUnitAmountMap.get(projectUid);
            if (projectUnitAmount != 0) {
                projectTotalAmount = DoubleUtil.mul(cnt, projectUnitAmount);
            }
            projectTotalAmountCnt = DoubleUtil.sum(projectTotalAmountCnt, projectTotalAmount);

            projectTotalAmountMap.put(projectUid, projectTotalAmount);
        }

        for (Table.Cell<String, Integer, Integer> cell : cntTable.cellSet()) {
            String projectUid = cell.getRowKey();
            Integer consumeType = cell.getColumnKey();
            Integer cnt = cell.getValue();

            double projectTotalAmount = projectTotalAmountMap.get(projectUid);
            // 服务的金额比例
            double radioAmount = 0;
            // 服务的金额比例*订单金额
            double orderAmountRadioAmount = 0;
            // 平均单价
            double unitAmount = 0;
            if (projectTotalAmount != 0) {
                // 服务的金额比例
                radioAmount = DoubleUtil.divFloor(projectTotalAmount, projectTotalAmountCnt, 6);
                // 服务的金额比例*订单金额
                orderAmountRadioAmount = DoubleUtil.mul(radioAmount, orderAmount, 6);
                unitAmount = DoubleUtil.divFloor(orderAmountRadioAmount, cnt, 4);
            }
//            System.out.println("amountRadioAmount = " + orderAmountRadioAmount);
//            System.out.println("unitAmount = " + unitAmount);

            List<Cmservices> list = serviceMap.get(projectUid);
            for (Cmservices service : list) {
                double totalAmount = 0d;
                if (unitAmount > 0)
                    if (consumeType.equals(1)) {
                        totalAmount = DoubleUtil.mul(service.getTotalLessons(), unitAmount);
                    } else {
                        totalAmount = DoubleUtil.mul(service.getServiceDays(), unitAmount);
                    }
                cmservicesService.updateAmount(service.getUid(), totalAmount, unitAmount);
                // 编辑会员订单时，更新会员点名记录的服务单价
                if (editOrder)
                    callNamesService.updateUnitAmount(service.getUid(), unitAmount);
            }
        }

        return "";
    }

    /**
     * 体验订单处理
     */
    private String expOrder(boolean editOrder, Double orderAmount, List<Cmservices> serviceList) {
        int totalLessonCnt = 0;
        // 计算总课次数量
        for (Cmservices service : serviceList) {
            // 判断是否能排课且消耗课次
            if (CmorderUtil.isConsumeLesson(service.getLessonStatus(), service.getFreeStatus())) {
                int totalLesson = NepUtil.nullToZero(service.getTotalLessons());
                if (totalLesson <= 0)
                    return "服务总数量不正确，订单金额拆分失败";
                totalLessonCnt += totalLesson;
            }
        }

        if (totalLessonCnt > 0) {
            // 单课次金额
            double unitAmount = DoubleUtil.divFloor(orderAmount, totalLessonCnt, 4);
            for (Cmservices service : serviceList) {
                // 判断是否能排课且消耗课次
                if (CmorderUtil.isConsumeLesson(service.getLessonStatus(), service.getFreeStatus())) {
                    int totalLesson = NepUtil.nullToZero(service.getTotalLessons());
                    if (totalLesson <= 0)
                        return "服务总数量不正确，订单金额拆分失败";
                    double amount = DoubleUtil.mul(unitAmount, totalLesson);
                    cmservicesService.updateAmount(service.getUid(), amount, unitAmount);

                    // 编辑会员订单时，更新会员点名记录的服务单价
                    if (editOrder)
                        callNamesService.updateUnitAmount(service.getUid(), unitAmount);
                }
            }
        }
        return "";
    }

    /**
     * 按门店uid、服务uid、次数或天数，查询最接近的单价
     */
    private Map<String, Double> getProjectUnitAmountMap(String corpUid, String storeUid, Table<String, Integer, Integer> cntTable) {
        Map<String, Double> projectUnitAmountMap = new HashMap<>();
        for (Table.Cell<String, Integer, Integer> cell : cntTable.cellSet()) {
            String projectUid = cell.getRowKey();
            Integer consumeType = cell.getColumnKey();
            Integer cnt = cell.getValue();

            StoreProjectCycleDtoV2 projectCycle = cycleMapper.getDtoByProjectUidAndCnt(
                    AccountUtil.isSelfStore(corpUid), storeUid, projectUid, consumeType, cnt
            );
            if (projectCycle == null)
                return null;

            projectUnitAmountMap.put(projectCycle.getProjectUid(), NepUtil.nullToZero(projectCycle.getUnitAmount()));
        }

        return projectUnitAmountMap;
    }


    /**
     * 编辑会员订单时，更新服务的单价和课耗的单价为0
     */
    private void setServiceZero(boolean editOrder, List<Cmservices> serviceList) {
        for (Cmservices service : serviceList) {
            cmservicesService.updateAmount(service.getUid(), 0, 0);
            // 更新会员点名记录的服务单价
            if (editOrder)
                callNamesService.updateUnitAmount(service.getUid(), 0);
        }
    }

}
